using System;
using System.Linq;
using BSpec.Specification;
using BSpec.Specs;
using NUnit.Framework;

namespace context_specs
{
    namespace with_scenario_of
    {
        public abstract class creating_a_context_from_a_test_fixture_type : SpecificationBase<Context>
        {
            protected Type test_fixture_type;

            protected override void setup_scenario()
            {
            }

            protected override Context create_subject()
            {
                return Context.Create(test_fixture_type);
            }
        }

        public abstract class adding_behaviours_to_a_context
            : creating_a_context_from_a_test_fixture_type
        {
        }
    }

    namespace given_a_type_that_contains_a_test_fixture
    {
        [TestFixture]
        public class when_creating_a_context : with_scenario_of.creating_a_context_from_a_test_fixture_type
        {
            protected override void setup_scenario()
            {
                test_fixture_type = this.GetType();
            }

            protected override void execute_scenario()
            {
                with_scenario_result(() => the_subject);
            }

            [Test]
            public void should_be_named_for_the_test_fixture_context()
            {
                the_scenario_result<Context>().Name.should_equal("Given a type that contains a test fixture");
            }
        }
    }

    namespace given_a_type_that_does_not_contain_a_context
    {
        [TestFixture]
        public class when_creating_a_context : with_scenario_of.creating_a_context_from_a_test_fixture_type
        {
            protected override void setup_scenario()
            {
                test_fixture_type = typeof(string);
            }

            protected override void execute_scenario()
            {
                with_scenario_result(() => the_subject);
            }

            [Test]
            public void should_return_a_null_context()
            {
                the_scenario_result<Context>().should_be_instance_of<NullContext>();
            }
        }
    }

    namespace given_a_context
    {
        [TestFixture]
        public class when_adding_a_behaviour : with_scenario_of.adding_behaviours_to_a_context
        {
            protected override void setup_scenario()
            {
                test_fixture_type = this.GetType();
            }

            protected override void execute_scenario()
            {
                the_subject.AddBehaviourFor(test_fixture_type);
            }

            [Test]
            public void should_add_the_behaviour_to_the_context()
            {
                the_subject.Behaviours.should_not_be_empty();
            }

            [Test]
            public void should_add_observations_to_the_behaviour()
            {
                the_subject.Behaviours.First().Observations.should_not_be_empty();
            }
        }
    }

    namespace given_a_context_contains_a_behaviour
    {
        [TestFixture]
        public class when_adding_a_behaviour_that_already_exists : with_scenario_of.adding_behaviours_to_a_context
        {
            protected override Context create_subject()
            {
                return Context.Create(this.GetType());
            }

            protected override void execute_scenario()
            {
                the_subject.AddBehaviourFor(this.GetType());
                the_subject.AddBehaviourFor(this.GetType());
            }

            [Test]
            public void should_not_add_duplicate_behaviours()
            {
                the_subject.Behaviours.Length.should_equal(1);
            }
        }
    }
}